package AG;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Random;
import AG.CromosomaPrograma;
import FactoriaCromosomas.FactoriaCrom;
import Herramientas.DatosGraficas;
import Herramientas.MyRandom;
import Herramientas.dupla;

public class Agenetico {
	private ArrayList<Cromosoma> pob;
	private int tamPob;
	private int num_max_generaciones;
	private Cromosoma elMejor;
	// private Cromosoma mejorGeneracion;
	private double mediaGeneracion;
	private static int pos_mejor; // ï¿½?ï¿½? ï¿½porquï¿½
									// estï¿½tico?
	private double prob_cruce;
	private double prob_mut;
	private double tolerance;
	private int generacionActual;
	private boolean maximizar;
	private double cmax, cmin;
	private int tamElite;
	private boolean cruceIntermedio;
	private int n;
	private int tipoInicializacion;

	/**
	 * CONSTRUCTURA
	 * 
	 * @param tamPob
	 *            tamaï¿½o de la poblacion
	 * @param numGener
	 *            numero de generaciones
	 * @param probCruce
	 *            probabilidad de cruce
	 * @param probMut
	 *            probabilidad de mutaciï¿½n
	 * @param tolerance
	 *            tolerancia
	 * @param maximizar
	 *            true (maximizar) o false (minimizar)
	 * @param cruceIntermedio
	 *            true (cruce a nivel de bit) o false (a nivel de genes)
	 * @param n
	 *            (nï¿½mero de genes de la funciï¿½n 4)
	 */
	public Agenetico(int tamPob, int numGener, double probCruce,
			double probMut, double tolerance, boolean maximizar,
			boolean cruceIntermedio, int n, int tipoIni) {
		this.tamPob = tamPob;
		this.num_max_generaciones = numGener;
		this.prob_cruce = probCruce;
		this.prob_mut = probMut;
		this.tolerance = tolerance;
		this.generacionActual = 0;
		this.maximizar = maximizar;
		this.cruceIntermedio = cruceIntermedio;
		this.n = n;
		this.tipoInicializacion = tipoIni;
	}

	// ****************MUTADORAS Y ACCESORAS*****************************
	public ArrayList<Cromosoma> getPob() {
		return pob;
	}

	public void setPob(ArrayList<Cromosoma> pob) {
		this.pob = pob;
	}

	public int getTamPob() {
		return tamPob;
	}

	public void setTamPob(int tamPob) {
		this.tamPob = tamPob;
	}

	public int getNum_max_generaciones() {
		return num_max_generaciones;
	}

	public void setNum_max_generaciones(int num_max_generaciones) {
		this.num_max_generaciones = num_max_generaciones;
	}

	public Cromosoma getElMejor() {
		return elMejor;
	}

	public void setElMejor(Cromosoma elMejor) {
		this.elMejor = elMejor;
	}

	public int getPos_mejor() {
		return pos_mejor;
	}

	public void setPos_mejor(int pos_mejor) {
		this.pos_mejor = pos_mejor;
	}

	public double getProb_cruce() {
		return prob_cruce;
	}

	public void setProb_cruce(double prob_cruce) {
		this.prob_cruce = prob_cruce;
	}

	public double getProb_mut() {
		return prob_mut;
	}

	public void setProb_mut(double prob_mut) {
		this.prob_mut = prob_mut;
	}

	public double getTolerance() {
		return tolerance;
	}

	public void setTolerance(double tolerance) {
		this.tolerance = tolerance;
	}

	public boolean getMaximizar() {
		return maximizar;
	}

	public void setMaximizar(boolean maximizar) {
		this.maximizar = maximizar;
	}

	/*
	 * public Cromosoma getMejorGeneracion() { return mejorGeneracion; } public
	 * void setMejorGeneracion(Cromosoma mejorGeneracion) { this.mejorGeneracion
	 * = mejorGeneracion; }
	 */
	public double getMediaGeneracion() {
		return mediaGeneracion;
	}

	public void setMediaGeneracion(double mediaGeneracion) {
		this.mediaGeneracion = mediaGeneracion;
	}

	public void setGeneracionActual(int generacionActual) {
		this.generacionActual = generacionActual;
	}

	public int getGeneracionActual() {
		return generacionActual;
	}

	public double getCmax() {
		return cmax;
	}

	public void setCmax(double cmax) {
		this.cmax = cmax;
	}

	public double getCmin() {
		return cmin;
	}

	public void setCmin(double cmin) {
		this.cmin = cmin;
	}

	public int getTamElite() {
		return tamElite;
	}

	public void setTamElite(int tamElite) {
		this.tamElite = tamElite;
	}

	/**
	 * Crea una poblaciï¿½n con el nï¿½mero de individuos del tamaï¿½o
	 * de la poblaciï¿½n. Estos individuos ya tienen su genotipo, su fenotipo
	 * y su aptitud.
	 * 
	 * @param tipoCromosoma
	 *            indica la funciï¿½n que se ha escogido, para saber como
	 *            crear a cada individuo.
	 */
	public void inicializar() {
		// para el mejor
		Cromosoma c1 = FactoriaCrom.dameCromosoma(7, this.tolerance, this.n);
		c1.setAptitud(-Double.MAX_VALUE); // -infinito
		elMejor = c1;
		// Resto
		pob = new ArrayList<Cromosoma>();
		// System.out.println("--- POBLACION INICIAL ---");
		for (int i = 0; i < this.tamPob; i++) {
			Cromosoma c = FactoriaCrom.dameCromosoma(7, this.tolerance, this.n);
			c.inicializarCromosoma(this.tipoInicializacion);
			c.setFenotipo(((CromosomaPrograma) c).fenotipo());
			c.setAptitud(c.evaluar());
			pob.add(c);
			// System.out.println("  " + i + "       " + c.getAptitud());

		}
		// System.out.println("---------");

	}

	/**
	 * Calculamos la posiciï¿½n del mejor individuo, y la puntuaciï¿½n y
	 * puntuaciï¿½n acumulada de cada uno de ellos.
	 * 
	 * aquï¿½ las aptitudes ya estï¿½n transformadas, por lo que me da
	 * igual que sea maximizar o minimzar.
	 */
	public void evaluarPoblacion() {
		double punAcu = 0.0;
		double aptitudMejor = -Double.MAX_VALUE; // PONGO - Y MAX
		double sumaAptitud = 0.0;

		Iterator<Cromosoma> it = pob.iterator();
		int i = 0;
		// recorro la poblaciï¿½n, voy calculando la suma de las aptitudes y
		// me quedo con la posiciï¿½n del mejor
		while (it.hasNext()) {
			Cromosoma c = it.next();
			sumaAptitud += c.getAptitud();
			if (c.getAptitud() > aptitudMejor) {
				aptitudMejor = c.getAptitud();
				pos_mejor = i;
			}
			i++;
		}

		// recorro la poblaciï¿½n y calculo la puntuaciï¿½n y la
		// puntuaciï¿½n acumulada
		int j;
		for (j = 0; j < tamPob; j++) {
			pob.get(j).setPuntuacion(pob.get(j).getAptitud() / sumaAptitud);
			pob.get(j).setPuntuacion_acumulada(
					pob.get(j).getPuntuacion() + punAcu);
			punAcu = punAcu + pob.get(j).getPuntuacion();
		}

		// this.mejorGeneracion = pob.get(pos_mejor);

	}

	/**
	 * comprueba si ya han pasado todas las generaciones
	 * 
	 * @return true si es final, false si no.
	 */
	public boolean terminado() {
		return generacionActual == num_max_generaciones;
	}

	/**
	 * seleccionamos la poblaciï¿½n, dependiendo del tipo de selecciï¿½n
	 * escogida por el usuario
	 * 
	 * @param tipo
	 *            tipo de selecciï¿½n: ruleta, torneo, estocastico, restos
	 */
	public void seleccion(String tipo, double presionS, int generacion) {
		if (tipo.equals("ruleta")) {
			int[] supervivientes = new int[1]; // da igual, no lo voy a usar
			seleccionRuleta(0, supervivientes);
		} else if (tipo.equals("torneo")) {
			int z = 3; // nï¿½mero de cromosomas que lucharï¿½n en cada
						// pelea. Entre 2 o 3
			seleccionTorneo(0, z);
		} else if (tipo.equals("estocasticos")) {
			seleccionEstocastica(0);
		} else if (tipo.equals("restos")) {
			seleccionRestos();
		} else if (tipo.equals("ranking")) {
			// double presionSelectiva = 1.4;
			seleccionRanking(presionS);
		} else if (tipo.equals("propia")) {
			seleccionPropia(generacion);
		}
		/*
		 * seleccion por truncamiento cogemos una copia de la
		 * poblaciï¿½n.dividimos su aptitud entre todos por dos. y llevamos
		 * un int[tamPob] auxiliar, con el numero por el que dividir.
		 * 
		 * repetimos (i=0;i<tamPob;i++) sort(pob)
		 * superviviente[i]=posicion(primero); // no es una copia, es saber cual
		 * ocupa en la poblacion inicial pob.get(primero).setAptitud(
		 * pob.get(primero).getAptitud()/auxiliar[posicion(primero)];
		 * auxiliar[posicion(primero)]++;
		 */
	}

	private void seleccionPropia(int generacion) {

		Collections.sort(pob); // IMPLEMENTAR EL COMPARE TO!!!!!!
		ArrayList<Cromosoma> pobAux = new ArrayList<Cromosoma>();
		double presionSelectiva = 1 + (double) generacion
				/ this.getNum_max_generaciones();
		// especie de elitismo
		pobAux.add(pob.get(0).copia());// copio el primer elemento
		pobAux.add(pob.get(1).copia());// copio el segundo elemento
		int numElems = 2;
		double[] listaPuntuaciones = rankPopulation(presionSelectiva);
		double puntuacionAcumulada = listaPuntuaciones[listaPuntuaciones.length - 1];
		while (numElems < pob.size()) {
			double x = (double) (Math.random() * puntuacionAcumulada);
			if (x <= listaPuntuaciones[0]) { // selecciono el primer elemento.
				pobAux.add(pob.get(0).copia());
				numElems++;
			} else {
				for (int i = 1; i < listaPuntuaciones.length; i++) {
					if (x > listaPuntuaciones[i - 1]
							&& x <= listaPuntuaciones[i]) { // selecciono el
															// individuo i
						pobAux.add(pob.get(i).copia());
						numElems++;
					}
				}
			}
		}

		pob = new ArrayList<Cromosoma>();
		for (int j = 0; j < pobAux.size(); j++) {
			Cromosoma copiaP = pobAux.get(j).copia();
			pob.add(copiaP);
		}
	}

	/**
	 * SELECCION POR RANKING
	 * 
	 * Selecciona la población dependiendo de la posicion que ocupa en el
	 * ranking, que es la poblacion ordenada. Dependiendo de la presionSelectiva
	 * que se le pase, tendrá más probabilidad de coger a los altos que a los
	 * bajos. Con presionSelectiva = 1 => Tenemos la misma posibilidad de coger
	 * cualquier individuo. Con presionSelectiva = 2 => Tenemos el doble de
	 * opciones de coger el mejor que el individuo medio.
	 */
	private void seleccionRanking(double presionSelectiva) {

		Collections.sort(pob); // IMPLEMENTAR EL COMPARE TO!!!!!!
		ArrayList<Cromosoma> pobAux = new ArrayList<Cromosoma>();

		// especie de elitismo
		pobAux.add(pob.get(0).copia());// copio el primer elemento
		pobAux.add(pob.get(1).copia());// copio el segundo elemento
		int numElems = 2;
		double[] listaPuntuaciones = rankPopulation(presionSelectiva);
		double puntuacionAcumulada = listaPuntuaciones[listaPuntuaciones.length - 1];
		while (numElems < pob.size()) {
			double x = (double) (Math.random() * puntuacionAcumulada);
			if (x <= listaPuntuaciones[0]) { // selecciono el primer elemento.
				pobAux.add(pob.get(0).copia());
				numElems++;
			} else {
				for (int i = 1; i < listaPuntuaciones.length; i++) {
					if (x > listaPuntuaciones[i - 1]
							&& x <= listaPuntuaciones[i]) { // selecciono el
															// individuo i
						pobAux.add(pob.get(i).copia());
						numElems++;
					}
				}
			}
		}

		pob = new ArrayList<Cromosoma>();
		for (int j = 0; j < pobAux.size(); j++) {
			Cromosoma copiaP = pobAux.get(j).copia();
			pob.add(copiaP);
		}
	}

	/**
	 * Calcula la probabilidad de que cada individuo en el ranking sea elegido.
	 * 
	 * @param presionSelectiva
	 *            probabilidad de que los mejores sean elegidos sobre los
	 *            promedios.
	 * @return las probabilidades de cada individuo.
	 */
	private double[] rankPopulation(double presionSelectiva) {
		double[] listaProbabilidades = new double[this.getTamPob()]; // Array
																		// con
																		// las
																		// probabilidades
																		// de
																		// seleccion.
		for (int i = 0; i < listaProbabilidades.length; i++) {
			int tamanyo = this.getTamPob();
			double probabilidadElemI = (double) (i) / tamanyo; // no se si hace
																// falta el -1
																// en los dos o
																// en ninguno.
			probabilidadElemI = probabilidadElemI * 2 * (presionSelectiva - 1);
			probabilidadElemI = presionSelectiva - probabilidadElemI;
			probabilidadElemI = (double) probabilidadElemI
					* ((double) 1 / this.getTamPob());
			if (i != 0)
				listaProbabilidades[i] = listaProbabilidades[i - 1]
						+ probabilidadElemI;
			else
				listaProbabilidades[i] = probabilidadElemI;
		}
		return listaProbabilidades;
	}

	public void seleccionRestos() {
		int[] supervivientes = new int[pob.size()];
		int posSuperviviente = 0;
		// int totalCopias=0;
		// k es la poblacion.
		for (int i = 0; i < pob.size(); i++) {
			int numCopias = (int) (pob.size() * pob.get(i).getPuntuacion()); // pi*k
																				// //
																				// OJO!!!
																				// ERROR!!!!
			for (int j = 0; j < numCopias; j++) {
				supervivientes[posSuperviviente] = i;
				posSuperviviente++;
			}
		}
		// el resto, de momento, siempre con ruleta.
		seleccionRuleta(posSuperviviente, supervivientes);
	}

	public void seleccionEstocastica(int inicio) {
		double prob;
		double a;
		int[] supervivientes = new int[tamPob];
		int posSuperviviente = 0;

		// System.out.println("--- poblaciï¿½n seleccionada ---");
		// Se genera un nï¿½mero aleatorio, y para cada posicion de la
		// poblacion, se selecciona
		// el individuo en el que caiga el nï¿½mero de la fï¿½rmula en su
		// intevalo de puntuaciï¿½n acumulada
		prob = Math.random(); // ï¿½nico randoom.
		for (int i = inicio; i < tamPob; i++) {
			a = (prob + i) / tamPob;
			posSuperviviente = 0;
			while (a > pob.get(posSuperviviente).getPuntuacion_acumulada()
					&& (posSuperviviente < tamPob)) {
				posSuperviviente++;
			}
			supervivientes[i] = posSuperviviente;
		}
		// System.out.println();

		ArrayList<Cromosoma> pobAux = copiar(pob);
		// en pobAux tenemos la poblaciï¿½n copiada. Ahora hay que modificar
		// la poblaciï¿½n
		pob = new ArrayList<Cromosoma>();
		for (int i = 0; i < tamPob; i++) {
			Cromosoma copiaP = pobAux.get(supervivientes[i]).copia();
			pob.add(copiaP);
			// System.out.println("  " + supervivientes[i] + "     " +
			// pob.get(i).getFenotipo() + "        " + pob.get(i).getAptitud());
		}
	}

	/**
	 * Selecciono los individuos de la poblaciï¿½n original. Al final, queda
	 * el mismo nï¿½mero de individuos. Repito (tamPob) veces una lucha,
	 * entre z luchadores, y el mejor se queda en la poblaciï¿½n.
	 * 
	 * @param inicio
	 *            // nï¿½mero de individuos ya seleccionados, y desde donde
	 *            empezamos a seleccionar.
	 * @param z
	 *            // nï¿½mero de individuos en cada lucha
	 */
	private void seleccionTorneo(int inicio, int z) {
		int[] supervivientes = new int[tamPob];
		// System.out.println("---- poblacion seleccionada por torneo -------");

		for (int i = inicio; i < tamPob; i++) { // para cada posiciï¿½n a
												// seleccionar
			// primero, selecciono los elementos que van a combatir
			int ganador = 0;
			double puntuacionGanador = -Double.MAX_VALUE;
			// escojo los luchadores.
			for (int j = 0; j < z; j++) {
				double aux = Math.random() * (tamPob);
				int luchador = (int) Math.floor(aux);
				// gana el mejor
				if (pob.get(luchador).getAptitud() > puntuacionGanador) {
					ganador = luchador;
					puntuacionGanador = pob.get(luchador).getAptitud();
				}
			}
			supervivientes[i] = ganador;
		}

		ArrayList<Cromosoma> pobAux = copiar(pob);
		// en pobAux tenemos la poblaciï¿½n copiada. Ahora hay que modificar
		// la poblaciï¿½n original
		pob = new ArrayList<Cromosoma>();
		for (int i = 0; i < tamPob; i++) {
			Cromosoma copiaP = pobAux.get(supervivientes[i]).copia();
			pob.add(copiaP);
			// System.out.println("En la posicion  " + i + "  ha ganado: " +
			// supervivientes[i] + "   con una aptitud de:  " +
			// pob.get(i).getAptitud());
		}
		// System.out.println("---------------------------");
	}

	/**
	 * Selecciono los individuos de la poblaciï¿½n original. Al final, queda
	 * el mismo nï¿½mero de individuos. En ruleta, hago un random, y el
	 * nï¿½mero que coincida en el intervalo de las puntuaciones acumuladas
	 * con el individuo es el que escojo. Lï¿½gicamente, los que tienen
	 * mï¿½s puntuaciï¿½n tienen mï¿½s opciones de salir
	 * 
	 * @param inicio
	 *            // nï¿½mero de individuos ya seleccionados, y desde donde
	 *            empezamos a seleccionar.
	 * @param supervivientes
	 *            // individuos ya seleccionados por restos. Ahora quedan por
	 *            seleccionar los demï¿½s (Desde inicio a tamPob)
	 */
	private void seleccionRuleta(int inicio, int[] supervivientes) {
		double prob;
		// int[] supervivientes = new int[tamPob];
		if (inicio == 0)
			supervivientes = new int[tamPob];
		int posSuperviviente = 0;
		// System.out.println("--- poblaciï¿½n seleccionada ---");
		// para cada posiciï¿½n de la poblaciï¿½n, genero un nï¿½mero,
		// y en el intervalo de puntuaciones
		// acumuladas que estï¿½, cojo el individuo y le paso a la nueva
		// poblaciï¿½n.
		for (int i = inicio; i < tamPob; i++) {
			prob = Math.random();
			posSuperviviente = 0;
			while (prob > pob.get(posSuperviviente).getPuntuacion_acumulada()
					&& (posSuperviviente < tamPob)) {
				posSuperviviente++;
			}

			supervivientes[i] = posSuperviviente;
		}
		// System.out.println();

		ArrayList<Cromosoma> pobAux = copiar(pob);
		// en pobAux tenemos la poblaciï¿½n copiada. Ahora hay que modificar
		// la poblaciï¿½n
		pob = new ArrayList<Cromosoma>();
		for (int i = 0; i < tamPob; i++) {
			Cromosoma copiaP = pobAux.get(supervivientes[i]).copia();
			pob.add(copiaP);
			// System.out.println("  " + supervivientes[i] + "     " +
			// pob.get(i).getFenotipo() + "        " + pob.get(i).getAptitud());
		}
	}

	/**
	 * Crea una copia de una poblaciï¿½n de cromosomas.
	 * 
	 * @param pob2
	 *            poblacion a copiar
	 * @return poblacion copiada
	 */
	private ArrayList<Cromosoma> copiar(ArrayList<Cromosoma> pob2) {
		ArrayList<Cromosoma> copiada = new ArrayList<Cromosoma>();
		Iterator<Cromosoma> it = pob2.iterator();
		while (it.hasNext()) {
			Cromosoma c = it.next();
			Cromosoma CromosomaAux = c.copia();
			copiada.add(CromosomaAux);
		}
		return copiada;
	}

	/**
	 * Recorremos la poblaciï¿½n, y para cada individuo, hacemos un random, y
	 * si es mayor que la probabilidad de cruce, pasa a ser padre o madre. Si
	 * no, no se reproduce. Despuï¿½s, juntamos una parte del padre y otra de
	 * la madre para cada hijo, y se intercambian en la poblaciï¿½n.
	 */
	public void reproduccion(double pc) {
		// Array seleccionados para reproducir
		int[] reproductores = new int[tamPob];
		int num_seleccion_cruce = 0;
		int punto_cruce;
		double prob;

		// System.out.print("-- se van a reproducir: --");
		// escojo a los padres y a las madres
		for (int i = 0; i < tamPob; i++) {
			prob = Math.random();
			if (prob < prob_cruce) {
				reproductores[num_seleccion_cruce] = i;
				num_seleccion_cruce++;
				// System.out.print(i + " ; " );
			}
		}
		// Hacemos par el numero de indivuos a realizar el coito
		if (num_seleccion_cruce % 2 == 1) {
			num_seleccion_cruce--;

		}

		// punto_cruce es el bit en el que se van a cambiar en caso de ser a
		// nivel de bits. Si no, calculamos el gen al que pertenece ese bit
		/*
		 * aquï¿½ vendrï¿½a un bucles desde 0 hasta NUMEROPUNTOSDECRUCE,
		 * que me genera un nï¿½mero aleatorio, y lo guarda en un Array de
		 * nï¿½meros llamado Cruces, que luego se pasa a crucePunto.
		 * IMPORTANTE: meter antes de esto, el 0 a Cruces, y despuï¿½s, la
		 * Longitud del Cromosoma-1
		 */
		/*ArrayList<Integer> Cruces = new ArrayList<Integer>();
		Random m = new Random();*/

		// System.out.println("ANTES DEL CRUCE" );

		for (int i = 0; i < num_seleccion_cruce; i = i + 2) {
			/*Cruces = new ArrayList<Integer>();
			int index1 = m.nextInt(5);
			int index2 = index1;
			while (index1 == 0) {
				index1 = m.nextInt(5);
			}

			while (index1 == index2 || index2 == 0) {
				index2 = m.nextInt(5);
			}

			if (index1 > index2) {
				int aux = index2;
				index2 = index1;
				index1 = aux;
			}
			Cruces.add(index1);
			Cruces.add(index2);*/
			// System.out.println(Cruces.get(0));
			// System.out.println(Cruces.get(1));
			dupla Hijos = CromosomaPrograma.reproduce(
					(CromosomaPrograma) pob.get(reproductores[i]),
					(CromosomaPrograma) pob.get(reproductores[i + 1]), pc);
			Hijos.getHijo1().setAptitud(Hijos.getHijo1().evaluar());
			Hijos.getHijo2().setAptitud(Hijos.getHijo2().evaluar());
			pob.set(reproductores[i], Hijos.getHijo1());
			pob.set(reproductores[i + 1], Hijos.getHijo2());

		}

	}

	/**
	 * Cambia el valor del bit que tiene que ser mutado. Recorro todos los
	 * individuos, y todos los bits, y si el random me da un valor menor que el
	 * de probabilidad de mutaciï¿½n, muto ese bit.
	 */
	public void mutacion(int tipoMutacion) {
		boolean mutado = false;
		int i, j;
		double prob;
		// System.out.println("Los que han mutado han sido: ");
		// System.out.println("ANTES DE MUTACION");
		for (i = 0; i < tamPob; i++) { // para cada individuo
			prob = Math.random();
			mutado = false;

			if (prob < prob_mut) { // muta
				CromosomaPrograma mutadoNuevo = CromosomaPrograma.muta(
						(CromosomaPrograma) pob.get(i), tipoMutacion,
						this.prob_mut);
				mutado = true;
				// System.out.print("el individuo " + i + " con aptitud:" +
				// pob.get(i).getAptitud());
				pob.set(i, mutadoNuevo.copia());

			}
			if (mutado) { // si un individuo ha sido mutado, recalculo su
				// fenotipo y su aptitud
				pob.get(i).setFenotipo(
						((CromosomaPrograma) pob.get(i)).fenotipo());
				pob.get(i).setAptitud(pob.get(i).evaluar());
			}
		}

	}

	/**
	 * Crea los hijos de la reproducciï¿½n.
	 * 
	 * @param padre
	 *            individuo que crea descendiente
	 * @param madre
	 *            individuo que crea descendiente
	 * @param puntoCruce
	 *            bit por el que se va a producir el cruce (o bit del que sacar
	 *            el gen por el que se va a cruzar)
	 * @return dupla de cromosomas con los dos hijos creados.
	 */
	public dupla crucePunto(Cromosoma padre, Cromosoma madre,
			ArrayList<Integer> Cruces) {
		Cromosoma hijo = null;
		Cromosoma hija = null;

		// inicializamos a los hijos, dependiendo del tipo de funciï¿½n
		/*
		 * if(padre instanceof cromosomaFuncion1){ hijo =
		 * FactoriaCrom.dameCromosoma(1,tolerance,this.n); hija =
		 * FactoriaCrom.dameCromosoma(1,tolerance,this.n);
		 * hijo.inicializarCromosoma(); hija.inicializarCromosoma(); } else{
		 * if(padre instanceof cromosomaFuncion2){ hijo =
		 * FactoriaCrom.dameCromosoma(2,tolerance,this.n); hija =
		 * FactoriaCrom.dameCromosoma(2,tolerance,this.n);
		 * hijo.inicializarCromosoma(); hija.inicializarCromosoma(); } else
		 * if(padre instanceof cromosomaFuncion3){ hijo =
		 * FactoriaCrom.dameCromosoma(3,tolerance,this.n); hija =
		 * FactoriaCrom.dameCromosoma(3,tolerance,this.n);
		 * hijo.inicializarCromosoma(); hija.inicializarCromosoma(); } else
		 * if(padre instanceof cromosomaFuncion4){ hijo =
		 * FactoriaCrom.dameCromosoma(4,tolerance,this.n); hija =
		 * FactoriaCrom.dameCromosoma(4,tolerance,this.n);
		 * hijo.inicializarCromosoma(); hija.inicializarCromosoma(); } else
		 * if(padre instanceof cromosomaFuncion5){ hijo =
		 * FactoriaCrom.dameCromosoma(5,tolerance,this.n); hija =
		 * FactoriaCrom.dameCromosoma(5,tolerance,this.n);
		 * hijo.inicializarCromosoma(); hija.inicializarCromosoma(); } }
		 * 
		 * if (cruceIntermedio==true){ // cruce a nivel de bits
		 * 
		 * aquï¿½ habrï¿½ que hacer algo asï¿½ (cruces es un array con
		 * los puntos de cruce, Y Aï¿½ADO AL PRINCIPIO 0 Y AL FINAL
		 * LONGITUDCROMOSOMA) Cruces tiene que venir ordenado!! for (int k=0;
		 * k<Cruces.size()-1;k++) inicio = Cruces.get(k); fin = Cruces.get(k+1);
		 * if (k mod 2 = 0) --- hijo = padre, hija = madre (primer for, desde
		 * inicio hasta fin) else --- hijo = madre, hijo = padre (segundo for,
		 * desde inicio hasta fin)
		 * 
		 * 
		 * for(int k=0; k<(Cruces.size()-1);k++){
		 * 
		 * int inicio=Cruces.get(k); int fin=Cruces.get(k+1); if (k % 2 == 0){
		 * for(int i = inicio; i< fin; i++){ int tamAcumulado = 0; for(int j =0;
		 * j<hijo.dameGen(i);j++){ tamAcumulado+=((Gen)
		 * (hijo.getGenes().get(j))).getTamanoGen(); // calculo los bits de los
		 * genes anteriores al actual, para saber el bit del gen en el que estoy
		 * y tengo que asignar } // pongo bit a bit al hijo lo del padre, y a la
		 * hija lo de la madre
		 * hijo.getGenes().get(hijo.dameGen(i)).getAlelos().set(i-tamAcumulado,
		 * padre
		 * .getGenes().get(hijo.dameGen(i)).getAlelos().get(i-tamAcumulado));
		 * hija.getGenes().get(hijo.dameGen(i)).getAlelos().set(i-tamAcumulado,
		 * madre
		 * .getGenes().get(hija.dameGen(i)).getAlelos().get(i-tamAcumulado)); }
		 * } else{ for(int i = inicio; i< fin; i++){ int tamAcumulado = 0;
		 * for(int j =0; j<hijo.dameGen(i);j++){
		 * tamAcumulado+=((Gen)hijo.getGenes().get(j)).getTamanoGen(); //
		 * calculo los bits de los genes anteriores al actual, para saber el bit
		 * del gen en el que estoy y tengo que asignar } // pongo bit a bit al
		 * hijo lo de la madre, y a la hija lo del padre
		 * hijo.getGenes().get(hijo.dameGen(i)).getAlelos().set(i-tamAcumulado,
		 * madre
		 * .getGenes().get(hijo.dameGen(i)).getAlelos().get(i-tamAcumulado));
		 * hija.getGenes().get(hijo.dameGen(i)).getAlelos().set(i-tamAcumulado,
		 * padre
		 * .getGenes().get(hija.dameGen(i)).getAlelos().get(i-tamAcumulado)); }
		 * } } } else{ // cruce a nivel de genes
		 * 
		 * aquï¿½ habrï¿½ que hacer algo asï¿½ (cruces es un array con
		 * los puntos de cruce, Y Aï¿½ADO AL PRINCIPIO 0 Y AL FINAL
		 * LONGITUDCROMOSOMA) Cruces tiene que venir ordenado!! for (int k=0;
		 * k<Cruces.size()-1;k++) inicio = Cruces.get(k); fin = Cruces.get(k+1);
		 * if (k mod 2 = 0) --- hijo = padre, hija = madre (primer for, desde
		 * inicio hasta fin) else --- hijo = madre, hijo = padre (segundo for,
		 * desde inicio hasta fin)
		 * 
		 * //int hastaGen=padre.dameGen(puntoCruce); for(int k=0;
		 * k<(Cruces.size()-1);k++){ int inicio=Cruces.get(k); int
		 * fin=Cruces.get(k+1); if (k % 2 == 0){ // pongo gen a gen al hijo lo
		 * del padre, y a la hija lo de la madre for (int i = inicio; i <fin;
		 * i++){ hijo.getGenes().set(i, padre.getGenes().get(i));
		 * hija.getGenes().set(i, madre.getGenes().get(i)); } } else{ // pongo
		 * gen a gen al hijo lo de la madre, y a la hija lo del padre for (int
		 * j=inicio; j<fin;j++ ){ hijo.getGenes().set(j,
		 * madre.getGenes().get(j)); hija.getGenes().set(j,
		 * padre.getGenes().get(j)); } } } }
		 * 
		 * // calculo fenotipos y aptitudes de los hijos. Puntuaciones no hace
		 * falta!, porque se harï¿½ en la siguiente fase en evaluar
		 * hijo.setFenotipo(hijo.fenotipo()); hija.setFenotipo(hija.fenotipo());
		 * if(maximizar==false){ // minimizar
		 * hijo.setAptitud(cmax-hijo.evaluar());
		 * hija.setAptitud(cmax-hija.evaluar()); } else{
		 * hijo.setAptitud(hijo.evaluar()-cmin);
		 * hija.setAptitud(hija.evaluar()-cmin); }
		 */
		dupla d = new dupla();
		d.setHijo1(hijo);
		d.setHijo2(hija);
		return d;

	}

	/**
	 * METODO DE TRANSFORMACIï¿½N transforma las aptitudes mï¿½nimas
	 * negativas a las mï¿½ximas positivas, para que no haya diferencia entre
	 * minimizar y maximizar en las funciones de selecciï¿½n, mutaciï¿½n,
	 * reproducciï¿½n....
	 */
	private void revisarAdaptacionMinimizar() {
		cmax = -(Double.MAX_VALUE);
		// obtengo la aptitud mï¿½xima
		for (int i = 0; i < pob.size(); i++) {
			if (cmax < pob.get(i).getAptitud())
				cmax = pob.get(i).getAptitud();
		}

		if (cmax > 0) { // aumento un poco su valor para que despuï¿½s no
						// haya ninguna aptitudo con valor 0
			cmax = cmax * 1.05;
		} else {
			cmax = cmax * 0.95;
		}

		// System.out.println("La poblacion transformada ha quedado así: ");
		// transformo
		for (int j = 0; j < pob.size(); j++) {
			pob.get(j).setAptitud(cmax - pob.get(j).getAptitud());
			// System.out.println(j + " tiene una aptitud de: " +
			// pob.get(j).getAptitud());
		}
	}

	/**
	 * METODO DE DESPLAZAMIENTO desplaza las aptitudes para que no haya ninguna
	 * negativa, y despuï¿½s no haya problemas con la suma de las aptitudes y
	 * demï¿½s.
	 */
	private void revisarAdaptacionMaximizar() {
		cmin = Double.MAX_VALUE;
		// busco la aptitud mï¿½nima
		for (int i = 0; i < pob.size(); i++) {
			if (cmin > pob.get(i).getAptitud())
				cmin = pob.get(i).getAptitud();
		}

		// si hay alguno negativo, tengo que hacer desplazamiento
		if (cmin < 0) {
			for (int j = 0; j < pob.size(); j++) {
				pob.get(j).setAptitud(pob.get(j).getAptitud() - cmin);
			}
		} else {
			cmin = 0;
		}
	}

	/**
	 * REVERTIR LA TRANSFORMACIï¿½N vuelve a los valores anteriores de la
	 * aptitud. Revierte la transformaciï¿½n. Calcula la media de la
	 * generacion
	 */
	private void revertirRevisarAdaptacionMinimizar() {
		double sumaAptitud = 0;
		int pm = -1;
		double mejorAptitud = Integer.MAX_VALUE;
		for (int i = 0; i < tamPob; i++) {
			// pob.get(i).setAptitud(cmax-pob.get(i).getAptitud());
			pob.get(i).setAptitud(pob.get(i).evaluar());
			if (mejorAptitud > pob.get(i).getAptitud()) {
				mejorAptitud = pob.get(i).getAptitud();
				pm = i;
			}
			sumaAptitud += pob.get(i).getAptitud();
		}
		this.mediaGeneracion = sumaAptitud / tamPob;
		this.pos_mejor = pm;
		// System.out.println("media Generacion:  " + this.mediaGeneracion );
		// System.out.println("mejor: " + pm + " con aptitud de: " +
		// pob.get(pm).getAptitud());
	}

	/**
	 * REVERTIR EL DESPLAZAMIENTO vuelve a los valores anteriores de la aptitud.
	 * Revierte el desplazamiento
	 */
	private void revertirRevisarAdaptacionMaximizar() {
		double sumaAptitud = 0;
		for (int i = 0; i < pob.size(); i++) {
			// pob.get(i).setAptitud(pob.get(i).getAptitud()+cmin);
			//pob.get(i).setAptitud(pob.get(i).evaluar());
			sumaAptitud += pob.get(i).getAptitud();
		}
		this.mediaGeneracion = sumaAptitud / tamPob;
	}

	/**
	 * ordena los cromosomas por su aptitud, y cogemos los mejores, que
	 * serï¿½n la ï¿½lite, para que pasen directamente a la siguiente
	 * fase, y guardar los mejores. La ï¿½lite no se excluye de la
	 * poblaciï¿½n, por lo que estarï¿½n en los mï¿½todos de
	 * selecciï¿½n, reproducciï¿½n y mutaciï¿½n.
	 * 
	 * @param tam
	 *            tamaï¿½o de la ï¿½lite
	 * @return un arrayList con los mejores individuos de la poblaciï¿½n, la
	 *         Elite
	 */
	public ArrayList<Cromosoma> seleccionaElite(int tam) {
		ArrayList<Cromosoma> aux = new ArrayList<Cromosoma>();
		Collections.sort(this.getPob());
		for (int i = 0; i < tam; i++) {
			aux.add(this.getPob().get(i).copia());
		}
		return aux;
	}

	/**
	 * Vuelve a incluir a los mejores, que estaban en la ï¿½lite, en lugar de
	 * los peores.
	 * 
	 * @param elite
	 *            arrayList con la ï¿½lite que se habï¿½a copiado al
	 *            principio de la generaciï¿½n
	 */
	private void incluye(ArrayList<Cromosoma> elite) {
		this.getPob().addAll(elite);
		Collections.sort(this.getPob());
		for (int i = 0; i < this.getTamElite(); i++) {
			this.getPob().remove(pob.size() - 1);
		}
		// System.out.println(pob.size() + " TAMAï¿½O REAL");
		// System.out.println(this.getTamPob() + "TAmaï¿½o ideal");
	}

	public static DatosGraficas ejecuta(int tipoIni, boolean elitismo,
			int poblacion, int nGen, double pc, double pm, int tipoSeleccion,
			int tipoMutacion, double presionS) {
		Double mejorPuntuacionGlobal;
		ArrayList<Cromosoma> elite = null;
		String tipofunSeleccion = "torneo";
		// TRATAR
		if (tipoSeleccion == 1) {
			tipofunSeleccion = "ruleta";
		} else if (tipoSeleccion == 2) {
			tipofunSeleccion = "torneo";
		} else if (tipoSeleccion == 3) {
			tipofunSeleccion = "estocasticos";
		} else if (tipoSeleccion == 4) {
			tipofunSeleccion = "restos";
		} else if (tipoSeleccion == 5) {
			tipofunSeleccion = "ranking";
		} else if (tipoSeleccion == 6) {
			tipofunSeleccion = "propia";
		}
		ArrayList<Double> listaMejoresGen = new ArrayList<Double>();
		ArrayList<Double> listaMejoresGlobal = new ArrayList<Double>();
		ArrayList<Double> listaMediaGen = new ArrayList<Double>();
		// TO DO
		boolean maxim = true;

		Agenetico AG = new Agenetico(poblacion, nGen, pc, pm, 0.001, maxim,
				false, 2, tipoIni);

		AG.inicializar(); // pasamos la funci�n que es, para saber como
							// inicializar cada individuo

		AG.setTamElite(AG.getTamPob() / 25); // y si se la pedimos al usuario??

		// transformo las aptitudes!!
		if (AG.getMaximizar() == false) { // estoy minimizando
			AG.revisarAdaptacionMinimizar();
			mejorPuntuacionGlobal = Double.MAX_VALUE;
		} else {
			AG.revisarAdaptacionMaximizar();
			mejorPuntuacionGlobal = -Double.MAX_VALUE;
		}

		AG.evaluarPoblacion();
		int generacion = 0;
		while (!AG.terminado() && AG.getElMejor().getAptitud() <1.0) {
			generacion++;
			System.out.println("  empieza la generacion:" + generacion);
			// System.out.println("POS  ||          FENOTIPO       ||  APTITUD     ");
			AG.evaluarPoblacion(); // para recalcular Puntuaciones. HAY QUE
									// PONERLO, PUES SI NO RESTOS TIENE ALGUNA
									// PUNTUACI�N NEGATIVA
			AG.setGeneracionActual(AG.getGeneracionActual() + 1);

			// ELITISMO
			if (elitismo == true) {
				elite = AG.seleccionaElite(AG.getTamElite());
			}

			
			AG.seleccion(tipofunSeleccion, presionS, generacion);
			
			AG.reproduccion(pc);
			
			AG.mutacion(tipoMutacion);
			

			// ELITISMO
			if (elitismo == true) {
				AG.incluye(elite);
			}
			// System.out.println("ANTES DE EVALUAR");
			AG.evaluarPoblacion(); // para saber el mejor

			if (AG.getMaximizar() == false) { // estoy minimizando
				AG.revertirRevisarAdaptacionMinimizar();
			} else {
				AG.revertirRevisarAdaptacionMaximizar();
			}

			/*
			 * System.out.println("---- En la vuelta " + k +
			 * "tenemos la siguiente poblacion despues de todo:  ------"); for
			 * (int i = 0; i <AG.getPob().size();i++){
			 * System.out.println("El individuo en la posicion " + i +
			 * " tiene una aptitud de: " + AG.getPob().get(i).getAptitud()); }
			 * System.out.println("ANTES DE CAMBIOS");
			 */
			// cambio el mejor de la generaci�n
			if (AG.getMaximizar() == true
					&& (AG.getPob().get(AG.getPos_mejor()).getAptitud() > mejorPuntuacionGlobal)) {
				mejorPuntuacionGlobal = AG.getPob().get(AG.getPos_mejor())
						.getAptitud();
				AG.setElMejor(AG.getPob().get(AG.getPos_mejor()).copia());
			}
			if (AG.getMaximizar() == false
					&& (AG.getPob().get(AG.getPos_mejor()).getAptitud() < mejorPuntuacionGlobal)) {
				mejorPuntuacionGlobal = AG.getPob().get(AG.getPos_mejor())
						.getAptitud();
				AG.setElMejor(AG.getPob().get(AG.getPos_mejor()).copia());
			}

			// cojo el mejor, el mejor global hasta el momento, y la media de la
			// generaci�n
			// listaMejoresGen.add(AG.getMejorGeneracion().getAptitud());
			listaMejoresGen.add(AG.getPob().get(AG.getPos_mejor()).getAptitud());
			listaMejoresGlobal.add(mejorPuntuacionGlobal);
			listaMediaGen.add(new Double(AG.getMediaGeneracion()));

			/*
			 * System.out.println("Posicion Mejor: " + AG.getPos_mejor());
			 * System.out.println("Fenotipo: " +
			 * AG.getPob().get(AG.getPos_mejor()).getFenotipo());
			 * System.out.println("Aptitud:  " +
			 * AG.getPob().get(AG.getPos_mejor()).getAptitud());
			 * System.out.println
			 * ("--------------------------------------------------");
			 */

			if (AG.getMaximizar() == false) { // estoy minimizando
				AG.revisarAdaptacionMinimizar();
			} else {
				AG.revisarAdaptacionMaximizar();
			}
			System.out.println("GENERACION ACTUAL: " + AG.getGeneracionActual());
			System.out.println("  CON APTITUD= " + AG.getElMejor().getAptitud());

		}
		if (AG.getMaximizar() == false) { // estoy minimizando
			AG.revertirRevisarAdaptacionMinimizar();
		} else {
			AG.revertirRevisarAdaptacionMaximizar();
		}


		
		  System.out.println("MEJOR FINAL!!!!!!!!!");
		  System.out.println(  ((CromosomaPrograma)AG.getElMejor()).getArbol().toString());
		  System.out.println(listaMejoresGen.get(AG.generacionActual-1));
		  /* * System.out.println(); System.out.println("Kilometros " +
=======
		
		  System.out.println("MEJOR FINAL!!!!!!!!!");
		  System.out.println("Fenotipo: " + ((CromosomaPrograma)AG.getElMejor()).getArbol().toString());
		/* System.out.println(); System.out.println("Kilometros " +
>>>>>>> .r93
		 * ((CromosomaCiudades)(AG.getElMejor())).evaluar());
		 * 
		 * 
		 * System.out.println("--------------------------------------------------"
		 * );
		 */
		// Graficas g = new Graficas();
		// g.pintarGrafica("funcion",listaMejoresGen, listaMejoresGlobal,
		// listaMediaGen);
		DatosGraficas dt = new DatosGraficas();
		dt.setElem1(listaMejoresGen);
		dt.setElem2(listaMejoresGlobal);
		dt.setElem3(listaMediaGen);
		dt.setElMejor(AG.getElMejor());
		dt.setNumGeneraciones(AG.generacionActual);
		return dt;
	}

	public static void main(String args[]) {
		int tipoMutacion = 3;
		int tipoSeleccion = 2; //torneo es 2. ruleta es 1

		DatosGraficas dt = Agenetico.ejecuta(1, true, 100, 100, 0.0, 0.9, tipoSeleccion,tipoMutacion, 1.0);


		System.out.println(dt.getElMejor().getAptitud());
	}

}
